package cn.pkubangbang.demo.democontact.interceptor;

import cn.pkubangbang.demo.democontact.service.AuthService;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * @Author: zhangzhenbang@k2data.com.cn
 * @Date: 2018-08-24 11:46
 */
public class AuthenticationInterceptor implements HandlerInterceptor {

    @Autowired
    private AuthService authService;

    private static Logger logger = LoggerFactory.getLogger(AuthenticationInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
        Object handler) throws Exception {

        // debug
        if (logger.isDebugEnabled()) {
            try {
                RequestDetail detail = getRequestDetail(request);
                logger.debug("got a request from {}, header->[\n{}], url->{}, uri->{}, query->{}",
                    detail.remoteAddress,
                    detail.headers,
                    detail.requestURL,
                    detail.requestURI,
                    detail.queryString);
            } catch (Exception ex) {
                // no-op
            }
        }

        // let go 'pre-flight' request
        String method = request.getMethod();
        if (HttpMethod.OPTIONS.name().equalsIgnoreCase(method)) {
            logger.debug("let go a pre-flight request for {}", request.getRequestURI());
            return true;
        }

        // note 取自 https://stackoverflow.com/questions/25373053/how-to-create-my-own-filter-with-spring-mvc
        String xHeader = request.getHeader("X-Auth-Token");
        logger.debug("got token {}", xHeader);
        boolean permitted = authService.getPermission(xHeader);
        if (permitted) {
            // 检查hitCount，防止频繁操作
            try {
                authService.touch(xHeader);
                return true;
            } catch (TooFrequentRequestException ex) {

                authService.invalid(xHeader);
                // em 拦截器里面如何添加更丰富的信息？
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                response.setContentType("text/plain");
                response.getWriter().print("Forbidden");
                return false;
            }
        } else {

            // em 是不是太简略了？
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("text/plain");
            response.getWriter().print("UnAuthorized");
            return false;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
        ModelAndView modelAndView) throws Exception {

        // no-op
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
        Object handler, Exception ex) throws Exception {

        // no-op
    }

    private static class RequestDetail {
        // remoteAddr, sb, requestURL, requestURI, queryString
        String remoteAddress;
        String headers;
        String requestURL;
        String requestURI;
        String queryString;

        RequestDetail(String remoteAddress, String headers, String requestURL,
            String requestURI, String queryString) {
            this.remoteAddress = remoteAddress;
            this.headers = headers;
            this.requestURL = requestURL;
            this.requestURI = requestURI;
            this.queryString = queryString;
        }
    }

    private RequestDetail getRequestDetail(HttpServletRequest request) {

        String remoteAddr = request.getRemoteAddr();

        Enumeration<String> headerNames = request.getHeaderNames();
        StringBuilder sb = new StringBuilder();
        if (headerNames != null) {
            while (headerNames.hasMoreElements()) {
                String nextElement = headerNames.nextElement();
                sb.append(nextElement).append("=>")
                    .append(request.getHeader(nextElement)).append("\n");
            }
        }

        StringBuffer requestURL = request.getRequestURL();
        String url = null;
        if (requestURL != null) {
            url = requestURL.toString();
        }

        String requestURI = request.getRequestURI();

        String queryString = request.getQueryString();

        return new RequestDetail(remoteAddr, sb.toString(), url, requestURI, queryString);
    }
}
